#include"Logger.hpp"
#include<iostream>
#include<vector>
#include<queue>
#include<unistd.h>
#include"Mutex.hpp"
#include"Thread.hpp"
#include"Cond.hpp"

const static int defaultthreadnum=3; 

template<class T>
class ThreadPool
{
private:
    bool QueueIsEmpty()
    {
        return _q.empty();
    }
    
    void Routine(const std::string&name)
    {
        while(true)
        {
            T t;
            {
                GuardMutex g(&_lock);
                while(QueueIsEmpty()&&_is_running)
                {
                    _wait_thread_num++;
                    _cond.Wait(_lock);
                    _wait_thread_num--;
                }
                if(!_is_running && QueueIsEmpty())
                {
                    LOG(Loglevel::INFO) << " 线程池退出 && 任务队列为空, " << name << " 退出";
                    break;
                }
                t=_q.front();
                _q.pop();
            }
            t();
            LOG(Loglevel::DEBUG) << name << " handler task: " << t.Result2String();
        }
    }
public:
    ThreadPool(int num=defaultthreadnum)
        :_threadnum(num),
        _wait_thread_num(0),
        _is_running(false)
    {
        for(int i=0;i<_threadnum;i++)
        {
            std::string name="thread"+std::to_string(i+1);
            _threads.emplace_back([this](const std::string &name)
            {this->Routine(name);},name);
        }
        LOG(Loglevel::INFO) << "thread pool obj create success";
    }
    void Start()
    {
        if(_is_running)
            return;
        _is_running=true;
        for(auto& thread:_threads)
        {
            thread.start();
        }
        LOG(Loglevel::INFO) << "thread pool running success";
    }
    // 核心思想：我们应该让线程走正常的唤醒逻辑退出
    // 线程池要退出
    // 1. 如果被唤醒 && 任务队列没有任务 = 让线程退出
    // 2. 如果被唤醒 && 任务队列有任务 = 线程不能立即退出，而应该让线程把任务处理完，在退出
    // 3. 线程本身没有被休眠，我们应该让他把他能处理的任务全部处理完成， 在退出
    // 3 || 2 -> 1
    // 如果任务队列有任务，线程是不会休眠的!
    void Stop()
    {
        if(!_is_running)
            return;
        _is_running=false;
        if(_wait_thread_num)
            _cond.NotifyAll();
    }
    void Wait()
    {
        for (auto &t : _threads)
        {
            t.join();
        }
        LOG(Loglevel::INFO) << "thread pool wait success";
    }
    void Enqueue(const T&t)
    {
        if(!_is_running)
            return;
        {
            GuardMutex g(&_lock);

            _q.push(t);
            if(_wait_thread_num > 0)
                _cond.NotifyOne();
        }
    }
    ~ThreadPool()
    {}
private:
    //任务队列
    std::queue<T> _q;

    //多个线程
    std::vector<Thread> _threads;
    int _threadnum;
    int _wait_thread_num;

    //保护机制
    Mutex _lock;
    Cond _cond;

    //是否运行
    bool _is_running;
};